﻿using NPOI.SS.Formula.Functions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Zocono.Infrastructure.Common;
using Zocono.WCS.Domain.DomainRepository;
using Zocono.WCS.Domain.EntityInfo;
using Zocono.WCS.Domain.PlcBytesObject;

namespace Zocono.WCS.Domain.BytesMapObjectDomain
{
    public class BytesMapObjectService : IBytesMapObjectService
    {
        private readonly IPlcConnectionInfoRepository _plcConnectionInfoRepository;
        private readonly IBytesMapObjectInfoRepository _bytesMapObjectInfoRepository;
        private readonly IBytesObjectServiceFactory _bytesObjectServiceFactory;
        private readonly IPlcReadDbInfoRepository _plcReadDbInfoRepository;
        private readonly ILogUtil _logUtil;
        private readonly IRedisHelper _IRedisHelper;

        public BytesMapObjectService(IRedisHelper iRedisHelper, IPlcReadDbInfoRepository plcReadDbInfoRepository, IPlcConnectionInfoRepository plcConnectionInfoRepository, IBytesMapObjectInfoRepository bytesMapObjectInfoRepository, IBytesObjectServiceFactory bytesObjectServiceFactory, ILogUtil logUtil)
        {
            _plcConnectionInfoRepository = plcConnectionInfoRepository;
            _bytesMapObjectInfoRepository = bytesMapObjectInfoRepository;
            _bytesObjectServiceFactory = bytesObjectServiceFactory;
            _plcReadDbInfoRepository = plcReadDbInfoRepository;
            _logUtil = logUtil;
            _IRedisHelper = iRedisHelper;
        }


        /// <summary>
        /// plcConnectionID获取Plc连接信息，获取相同的plcReadDbID，对应的BytesObjectBase报文类，如ZJNScMessagePlcActionBO、ZJNScMessageWcsActionBO。
        /// </summary>
        /// <param name="plcConnectionID"></param>
        /// <param name="plcReadDbID"></param>
        /// <param name="bytes">从PLC中读取的数据</param>
        /// <returns></returns>

        public async Task<List<BytesObjectBase>> ByteMapToObjectsAsync(long plcConnectionID, long plcReadDbID, byte[] bytes, List<BytesMapObjectInfo> bytesMapObjectInfos)
        {
            PlcConnectionInfo plcConn = new();
            //测试redis
            var plcConns = _IRedisHelper.GetStringKey<List<PlcConnectionInfo>>("PlcConnectionInfo");
            if (plcConns != null)
                plcConn = plcConns.Where(l => l.ID == plcConnectionID).Select(l => l).FirstOrDefault();
            if (plcConn == null || plcConns == null || plcConns.Count == 0)
            {
                plcConns = await _plcConnectionInfoRepository.GetListAsync();
                plcConn = plcConns.Where(l => l.ID == plcConnectionID).Select(l => l).FirstOrDefault();

                var saveOk = _IRedisHelper.SetStringKey("PlcConnectionInfo", plcConns, TimeSpan.FromDays(1));
                _logUtil.Info("Redis没有PlcConnectionInfo");
            }

            var plcReadDbs = await _plcReadDbInfoRepository.AsQueryable().Select(m => new PlcReadDbInfo
            {
                ID = m.ID,
                EquipmentCode = m.EquipmentCode
            }).ToListAsync();
            List<BytesObjectBase> Objects = new List<BytesObjectBase>();
            foreach (var bmo in bytesMapObjectInfos)
            {
                byte[] aobytes = new byte[bmo.BytesLength];
                //从bmo.BytesIndex起点开始将bytes复制到aobytes，bmo.BytesLength是aobytes接收的长度，0是aobytes接收的起点
                Array.Copy(bytes, bmo.BytesIndex, aobytes, 0, bmo.BytesLength);//第二次循环堆垛机例子：bytes不变，BytesIndex=48，BytesLength=32

                for (int index = 0; index < bmo.ObjectCount; index++)
                {
                    try
                    {
                        //解析报文对对应属性赋值
                        var bytesObject = CreratAsync(aobytes, index, bmo, plcConnectionID, plcReadDbID, plcConn);
                        //var bytesObject = await CreratAsync(aobytes, index, bmo, plcConnectionID, plcReadDbID, plcRead);
                        Objects.Add(bytesObject);
                        //if (plcReadDbID == 1574556847266992128 || plcReadDbID == 1574558335150198784)
                        //{
                        //    _logUtil.Debug($"交互解析出数据：【{JsonHelper.SerializeObject(bytesObject)}】");
                        //}
                    }
                    catch (Exception ex)
                    {
                        var plcReadTemp = plcReadDbs.FirstOrDefault(l => l.ID == plcReadDbID);
                        //var byteStr = "";
                        //for (int i = 0; i < aobytes.Length; i++)
                        //{
                        //    byteStr += aobytes[i] + ",";
                        //}
                        //_logUtil.Debug($"下标：{index} 报文index:[{bmo.BytesIndex}], plc连接id:[{plcConnectionID}], plcRead设备号:[{plcRead.EquipmentCode}] plcConnIP:[{plcConn.IP}] 读取报文信息为：[{byteStr}].交互解析出数据出错了ex=：【{ex.Message}】");
                        _logUtil.Debug($"【{plcConn.ScEquipmentCode}/{plcReadTemp?.EquipmentCode}】下标：{index} bytes长度：{aobytes.Length} 解析配置长度：{bmo.BytesLength} 解析类：{bmo.ObjectName} 交互解析出数据出错了ex=：【{ex.Message}】");
                    }
                }
            }

           // _logUtil.Debug($"ByteMapToObjectsAsync:{plcConnectionID},{plcReadDbID}");
            return Objects;
        }


        private BytesObjectBase CreratAsync(byte[] allObjectBytes, int index, BytesMapObjectInfo bmo, long plcConnectionID, long plcReadDbID, PlcConnectionInfo plcConn)
        {

            byte[] obytes = new byte[bmo.ObjectLength];
            int sIndex = index * bmo.ObjectLength;
            Array.Copy(allObjectBytes, sIndex, obytes, 0, bmo.ObjectLength);
            //创建报文对象
            var bytesObject = _bytesObjectServiceFactory.Create(bmo.ObjectName);
            //bytes序列化
            bytesObject.Serialize(plcConnectionID, plcReadDbID, bmo.BytesIndex, bmo.BytesLength, sIndex, bmo.ObjectLength, bmo.ObjectName, plcConn.ScEquipmentCode, obytes);

            return bytesObject;
        }


        #region 无需plc写设备号。数据库需要增加字段equipmentcode，将WCS报文的设备号直接复制


        public async Task<List<BytesObjectBase>> ByteMapToObjectsMonitorAsync(long plcConnectionID, long plcReadDbID, byte[] bytes, List<BytesMapObjectInfo> bytesMapObjectInfos)
        {
            PlcConnectionInfo plcConn = new();

            //测试redis
            var plcConns = _IRedisHelper.GetStringKey<List<PlcConnectionInfo>>("PlcConnectionInfo");
            if (plcConns != null)
                plcConn = plcConns.Where(l => l.ID == plcConnectionID).Select(l => l).FirstOrDefault();
            if (plcConn == null || plcConns == null || plcConns.Count == 0)
            {
                plcConns = await _plcConnectionInfoRepository.GetListAsync();
                //plcConn = await _plcConnectionInfoRepository.GetFirstAsync(p => p.ID == plcConnectionID);
                await _IRedisHelper.DeleteAsync("PlcConnectionInfo");
                var saveOk = _IRedisHelper.SetStringKey("PlcConnectionInfo", plcConns, TimeSpan.FromDays(1));
                _logUtil.Info("Redis没有PlcConnectionInfo");
            }
            List<BytesObjectBase> Objects = new();
            var plcReadDbs = await _plcReadDbInfoRepository.AsQueryable().Select(m => new PlcReadDbInfo
            {
                ID = m.ID,
                EquipmentCode = m.EquipmentCode
            }).ToListAsync();
            foreach (var bmo in bytesMapObjectInfos)
            {
                byte[] destinationBuff = new byte[bmo.BytesLength];
                //从bmo.BytesIndex起点开始将bytes复制到aobytes，bmo.BytesLength是aobytes接收的长度，0是aobytes接收的起点
                Array.Copy(bytes, bmo.BytesIndex, destinationBuff, 0, bmo.BytesLength);//第二次循环堆垛机例子：bytes不变，BytesIndex=48，BytesLength=32
               // Buffer.BlockCopy(bytes, bmo.BytesIndex, destinationBuff, 0, bmo.BytesLength);
                for (int index = 0; index < bmo.ObjectCount; index++)
                {
                    try
                    {
                        //解析报文对对应属性赋值
                        BytesObjectBase bytesObject;
                        //解析报文对对应属性赋值
                        if (!plcConn.ScEquipmentCode.Contains("Ele"))
                            bytesObject = CreratAsync(destinationBuff, index, bmo, plcConnectionID, plcReadDbID, plcConn);
                        else
                        {
                            var plcRead = plcReadDbs.FirstOrDefault(l => l.ID == plcReadDbID);
                            bytesObject = await CreratAsync(destinationBuff, index, bmo, plcConnectionID, plcReadDbID, plcRead);
                        }
                        Objects.Add(bytesObject);

                    }
                    catch (Exception ex)
                    {

                        var plcReadTemp = plcReadDbs.FirstOrDefault(l => l.ID == plcReadDbID);
  
                        _logUtil.Error($"【{plcConn.ScEquipmentCode}/{plcReadTemp?.EquipmentCode}】下标：{index} bytes长度：{destinationBuff.Length} 解析配置长度：{bmo.BytesLength} 解析类：{bmo.ObjectName} 监控解析出数据出错了ex=：【{ex.Message}】");
                    }
                }
            }

            return Objects;
        }



        private async Task<BytesObjectBase> CreratAsync(byte[] allObjectBytes, int index, BytesMapObjectInfo bmo, long plcConnectionID, long plcReadDbID, PlcReadDbInfo plcRead)
        {

            byte[] obytes = new byte[bmo.ObjectLength];
            int sIndex = index * bmo.ObjectLength;
            Array.Copy(allObjectBytes, sIndex, obytes, 0, bmo.ObjectLength);
            //创建报文对象
            var bytesObject = _bytesObjectServiceFactory.Create(bmo.ObjectName);
            //bytes序列化
            bytesObject.Serialize(plcConnectionID, plcReadDbID, bmo.BytesIndex, bmo.BytesLength, sIndex, bmo.ObjectLength, bmo.ObjectName, plcRead.EquipmentCode, obytes);

            return bytesObject;

        }

        #endregion



    }
}
